package client

import (
	"ChainCodeProject/block"
	"ChainCodeProject/tools"
	"ChainCodeProject/transaction"
	"flag"
	"fmt"
	"os"
)

/**
用户的程序交互接口
该模块只负责读取用户传递的命令和参数，并进行解析
再去调用对用的功能
*/
type Cli struct {
}

func (cl *Cli) Run() {
	//获取用户的所有的输入

	//确定有哪些功能，这些功能需不需要参数
	/**
		1.创建带有创世区块的区块链  参数：1  创世区块的交易信息
		main.exe createchain --data "交易"
		2.发起一笔交易  参数：3  新区块的交易信息
		main.exe send  --from “zhang”  --to “liu”  --amount  10
		3.获取区块链中所有区块的个数  参数：无
		main.exe getblockcount
	   	4.获取所有区块的信息  参数：无
		main.exe  allblock
		5.输出当前系统的使用说明  参数：无
		main.exe help
		6.生成比特币地址
		main.exe generateaddress
		7.判断地址是否合法
		main.exe checkaddr --address "要判断的地址"
		8.输出当前系统有哪些功能 参数：无
		9.获取对应地址的私钥 参数：addres
		main.exe GetPriKey --address "对应的地址"
	*/

	switch os.Args[1] {
	case "createchain":
		cl.createchain()
	case "send":
		cl.send()
	case "getblockcount":
		cl.getblockcount()
	case "allblock":
		cl.allblock()
	case "getbalance":
		cl.getbalance()
	case "help":
		cl.help()
	case "getprikey":
		cl.getprikey()
	case "generateaddress":
		cl.generateaddress()
	case "checkaddr":
		cl.checkaddr()
	default:
		fmt.Println("没有对应的功能")
		os.Exit(1)
	}
}

func (cl *Cli)getprikey(){
	getprikey := flag.NewFlagSet("getprikey", flag.ExitOnError)
	addr := getprikey.String("addr", "", "对应的地址")
	getprikey.Parse(os.Args[2:])
	chain,err := block.CreatChain(*addr)
	defer  chain.DB.Close()
	if err != nil{
		fmt.Println(err.Error())
		return
	}

	privateKey, err := chain.Wallet.ShowPrivateKey(*addr)
	if err != nil{
		fmt.Println(err.Error())
		return
	}
	fmt.Println("对应地址的私钥为:",privateKey)
}

func (cl *Cli) checkaddr() {
	checkaddr := flag.NewFlagSet("checkaddr", flag.ExitOnError)
	addr := checkaddr.String("addr", "", "要判断的地址")
	checkaddr.Parse(os.Args[2:])

	chain, err := block.CreatChain("")
	defer  chain.DB.Close()
	if err != nil{
		fmt.Println(err.Error())
		return
	}

	isture := chain.Wallet.CheckAddr(*addr)
	if isture {
		fmt.Println("地址合法！")
	} else {
		fmt.Println("地址不合法！")
	}

}

func (cl *Cli) generateaddress() {
	chain, err := block.CreatChain("")
	defer  chain.DB.Close()
	if err != nil{
		fmt.Println(err.Error())
		return
	}
	wlt := chain.Wallet
	addr,pri, err := wlt.NewAddress()
	if err != nil {
		fmt.Println("地址生成失败！")
		return
	}
	err = wlt.SavePrivateKey(pri, addr)
	if err != nil{
		fmt.Println(err.Error())
		return
	}
	fmt.Printf("生成的地址为：%s\n", addr)
}

func (cl *Cli) getbalance() {
	getbalance := flag.NewFlagSet("getbalance", flag.ExitOnError)
	address := getbalance.String("address", "", "查询地址")
	getbalance.Parse(os.Args[2:])


	exist := tools.FileExist("./chain.db")
	if !exist {
		fmt.Println("区块链不存在")
		return
	}
	//创建区块链对象
	chain, err := block.CreatChain("")
	defer chain.DB.Close()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	//判断地址是否合法
	istrue := chain.Wallet.CheckAddr(*address)
	if !istrue{
		fmt.Println("地址不合法！")
		return
	}
	balance := chain.GetBalance(*address)
	fmt.Printf("地址%s的余额为:%d", *address, balance)
}

func (cl *Cli) help() {
	fmt.Println("本系统有一下功能")
	fmt.Println("1.创建带有创世区块的区块链  参数：1  创世区块的交易信息")
	fmt.Println("2.向区块链去添加一个新区块  参数：1  新区块的交易信息")
	fmt.Println("3.获取区块链中所有区块的个数  参数：无")
	fmt.Println("4.获取所有区块的信息  参数：无")
	fmt.Println("5.输出当前系统的使用说明  参数：无")
}

func (cl *Cli) allblock() {
	//判断文件是否存在
	exist := tools.FileExist("./chain.db")
	if !exist {
		fmt.Println("未创建区块链!")
		return
	}
	bc, err := block.CreatChain("")
	defer bc.DB.Close()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	blocks, err := bc.GetAllBlock()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	for _, value := range blocks {
		//区块的hash
		fmt.Printf("hash:%x,交易个数:%d\n", value.Hash, len(value.Txs))
		//每一个交易的hash
		for _, tx := range value.Txs {
			fmt.Printf("\t交易hash：%x\n", tx.TXHash)
			fmt.Printf("\t\t有%d个交易输入\n", len(tx.Input))
			for index, input := range tx.Input {
				fmt.Printf("\t\t\t消费%d,来自%x,下标%d\n", index, input.Txid, input.Vout)
			}
			fmt.Printf("\t\t有%d个交易输出", len(tx.Output))
			for index, output := range tx.Output {
				fmt.Printf("\t\t\t收入%d,金额%d,属于%s\n", index, output.Value, output.ScriptPubKey)
			}
		}
	}

}

func (cl *Cli) getblockcount() {
	exist := tools.FileExist("./chain.db")
	if !exist {
		fmt.Println("区块链不存在!")
		return
	}
	bc, err := block.CreatChain("")
	defer bc.DB.Close()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	blocks, err := bc.GetAllBlock()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Printf("区块链一共有%d个区块", len(blocks))
}

//发起一笔交易，添加到区块链中
func (cl *Cli) send() {
	send := flag.NewFlagSet("send", flag.ExitOnError)
	from := send.String("from", "", "交易发起者的地址")
	to := send.String("to", "", "交易接收者的地址")
	amount := send.Uint("amount", 0, "交易金额")
	//解析参数
	send.Parse(os.Args[2:])

	//把交易放到区块中，在存储到区块链中
	chain, err := block.CreatChain("")
	defer  chain.DB.Close()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	//判断地址合不合法
	from_istrue := chain.Wallet.CheckAddr(*from)
	if !from_istrue {
		fmt.Println("from的地址不合法！")
		return
	}

	to_istrue := chain.Wallet.CheckAddr(*to)
	if !to_istrue {
		fmt.Println("to的地址不合法！")
		return
	}

	tx, err := chain.NewTransaction(*from, *to, *amount)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	//产生一个coinbase交易
	cb, err := chain.NewCoinBase(*from)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	err = chain.AddBlock([]transaction.Transaction{*tx, *cb})
	if err != nil {
		fmt.Println("交易添加失败!", err.Error())
	}
	fmt.Println("交易添加成功!")
}

func (cl *Cli) createchain() {
	//判断区块链是否存在
	exist := tools.FileExist("./chain.db")
	if exist {
		fmt.Println("区块链已存在！")
		return
	}
	//调用创建区块链的方法
	chain, err := block.CreatChain("")
	defer chain.DB.Close()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("区块链创建成功！")
}
